Function checkPHP ()
	Dim sList, iAnswer, sMessage, oThisServer, sPHPExecutable, aExtension, aPHPExtensions(), aPHPExecutables()
	Dim sRealExtension, sRealExecutable, iExtensionCount, sExtension, iCount, oFileSystem, oResult, sData
  
	On Error Resume Next

	'for the logging
	Const msiMessageTypeInfo = &H04000000
	Const msiMessageTypeError = &H01000000
	Const msiMessageTypeWarning = &H02000000
	Set record = Session.Installer.CreateRecord(0)
  	record.StringData(0) = "checkPHP.vbs -> checkPHP() -> begin"
	Session.Message msiMessageTypeInfo, record
	   		
	' Set label
	Session.Property("SCRIPTLabel") = "Checking for PHP (Version: " & Session.Property("SCRIPTVERSIONMIN") & " to " & Session.Property("SCRIPTVERSIONMAX") & ")"

	' Defaults
	iExtensionCount = 0
	Session.Property("SCRIPTCHECK") = "BAD"
  
	' Create IIS7 management object and file system object
	Set oFileSystem = CreateObject("Scripting.FileSystemObject")
	Set oWebAdmin = GetObject("winmgmts:root\WebAdministration")   'IIS7 WMI Namespace - requires that IIS managment tools are installed
	
	Set oFastCgi = oWebAdmin.Get("GlobalModulesSection.Location='',Path='MACHINE/WEBROOT/APPHOST'")
	oFastCgi.Get "GlobalModules", "Name='FastCgiModule'", oModule
	aExtension = Array(oModule.Image)
	if (Err.Number = 0) Then 
		isIIS7andFastCGIfound = true
		'Set record = Session.Installer.CreateRecord(0)
		record.StringData(0) = "checkPHP.vbs -> checkPHP() -> IIS7 -> found GlobalModule with Name=FastCgiModule"
		Session.Message msiMessageTypeInfo, record
	else
		'Set record = Session.Installer.CreateRecord(0)
		record.StringData(0) = "checkPHP.vbs -> checkPHP() -> IIS7 -> no GlobalModule with Name=FastCgiModule found"
		Session.Message msiMessageTypeInfo, record
		' Create IIS6 management object
		Err.Clear
		Set oThisServer = GetObject( "IIS://localhost/W3SVC" )
		' Get IIS extensions
		aExtension = oThisServer.ListExtensionFiles 
		' Error if IIS6 is not accessible
		If( Err.Number <> 0 ) Then 
			MsgBox "Unable to access IIS6 Management API" & _ 
			"please ensure that IIS is running" & vbCrLf & _ 
			"    - Error Details: " & Err.Description & " [Number:" & _
			Hex(Err.Number) & "]", vbCritical, "Error" 
			Session.Property("SCRIPTCHECK") = "BAD"
			checkPHP = ERROR_INSTALL_FAILURE 
			'Set record = Session.Installer.CreateRecord(0)
			record.StringData(0) = "checkPHP.vbs -> checkPHP() -> unable to list IIS extensions -> aborting"
			Session.Message msiMessageTypeError, record
			Exit Function 
		End if
	End if
    
	'loop through the extensions
	For iCount = LBound(aExtension)  To UBound(aExtension) 
        sExtension = aExtension(iCount)

        ' Check if extension contains the word php or fcgi
        if (InStr(1, LCase(sExtension), "php") <> 0) or (InStr(1, LCase(sExtension), "fcgi") <> 0) then
			' If fastcgi -> check mapping and get executable
			if InStr(1, LCase(sExtension), "fcgi") <> 0 Then
				if (isIIS7andFastCGIfound) then
					Set oFastCgi = oWebAdmin.Get("FastCgiSection.Location='',Path='MACHINE/WEBROOT/APPHOST'")
					fastCgiArray = oFastCgi.FastCgi
					for each entry in fastCgiArray
						if InStr(1, LCase(entry.FullPath), "php") <> 0 then
							sRealExecutable = entry.FullPath
							sRealExtension = entry.FullPath
							record.StringData(0) = "checkPHP.vbs -> checkPHP() -> found php mapping for FastCgi on IIS7"
							Session.Message msiMessageTypeInfo, record
							Exit For
						End if
					next
				else 'must be IIS6 with fastcgi instead
					sRealExtension = parseFastCgiIni(sExtension)
					sRealExecutable = sRealExtension
					record.StringData(0) = "checkPHP.vbs -> checkPHP() -> IIS6 with FastCGI mapping: " & sRealExecutable
					Session.Message msiMessageTypeInfo, record
				end if
			Elseif InStr(1, LCase(sExtension), "exe") <> 0 Then 		'currently we are looking for php exe's not isapi dlls 
				sRealExtension = sExtension
				sRealExecutable = getExecutable(sExtension)
				record.StringData(0) = "checkPHP.vbs -> checkPHP() -> no fastcgi / php executable: " & sRealExecutable
				Session.Message msiMessageTypeInfo, record
					If sRealExecutable = false Then
						Session.Property("SCRIPTCHECK") = "BAD"
						record.StringData(0) = "checkPHP.vbs -> checkPHP() -> no valid php executable found ->error"
						Session.Message msiMessageTypeInfo, record
						checkPHP = ERROR_INSTALL_FAILURE
						Exit function
					End if
			End if
			
			' Check if file exists
			If oFileSystem.FileExists(sRealExtension) Then
				' Get php file version
				sVersion = oFileSystem.GetFileVersion(sRealExtension)
				record.StringData(0) = "checkPHP.vbs -> checkPHP() -> checking: " & sRealExtension & " version: " & sVersion
				Session.Message msiMessageTypeInfo, record
				' Check version
				If Session.Property("SCRIPTVERSIONMIN") <= sVersion AND Session.Property("SCRIPTVERSIONMAX")  >= sVersion Then
					record.StringData(0) = "checkPHP.vbs -> checkPHP() -> version check successful"
					Session.Message msiMessageTypeInfo, record
					ReDim preserve aPHPExtensions(iExtensionCount)
					ReDim preserve aPHPExecutables(iExtensionCount)
                 	aPHPExtensions(iExtensionCount) = sExtension
					aPHPExecutables(iExtensionCount) = sRealExecutable
                 	sList = sList & vbCrLf & (iExtensionCount + 1) & ") " & sExtension
					iExtensionCount = iExtensionCount + 1
				End if        
			End if
			
		End if
	Next 


	If iExtensionCount = 1 then
		Session.Property("SCRIPTIISEXTENSION") = aPHPExtensions(0)
		Session.Property("SCRIPTEXECUTABLE") = aPHPExecutables(0)
		If checkPHPModules(Session.Property("SCRIPTEXECUTABLE")) Then
			Session.Property("SCRIPTCHECK") = "OK"
			record.StringData(0) = "checkPHP.vbs -> checkPHP() -> checkPHPModules() ok"
			Session.Message msiMessageTypeInfo, record
		End if
		if (Session.Property("checkIfIUSRisListedOnPHPUploadDir") = "1" ) then
			checkIfIUSRisListedOnPHPUploadDir
		end if
		record.StringData(0) = "checkPHP.vbs -> checkPHP() -> checkPHPModules() not ok -> error"
		Session.Message msiMessageTypeInfo, record
		Exit Function
	Elseif (iExtensionCount > 1) then
		sMessage = "The install process has detected more than one PHP IIS Extension:" & vbCrLF & sList & vbCrLf & vbCrLf & "and will now loop through these extensions. Do you want to you this one?" & vbCrLf
  		For iCount = LBound(aPHPExtensions) to UBound(aPHPExtensions)
			iAnswer = MsgBox(sMessage & aPHPExtensions(iCount) , 36, "Use PHP extension " & (iCount + 1) & "/" & iExtensionCount & "?")
			If Not iAnswer = 7 Then
				Session.Property("SCRIPTIISEXTENSION") = aPHPExtensions(iCount)
				Session.Property("SCRIPTEXECUTABLE") = aPHPExecutables(iCount)
				If checkPHPModules(Session.Property("SCRIPTEXECUTABLE")) Then
					Session.Property("SCRIPTCHECK") = "OK"
				End if
				if (Session.Property("checkIfIUSRisListedOnPHPUploadDir") = "1") then
					checkIfIUSRisListedOnPHPUploadDir
				end if
				Exit Function
			End If
		Next
	End if

	Session.Property("SCRIPTCHECK") = "BAD"
	checkPHP = ERROR_INSTALL_FAILURE

	
End Function

Function parseFastCgiIni(sExtension)
  Dim sIniFile, sResult, bSection, sSection
  Dim oFileSystem, oFile, sPath, sLine, iLineCount, aLines(), iCount
 
  On Error Resume Next
 
 	'for the logging
	Const msiMessageTypeInfo = &H04000000
	Const msiMessageTypeError = &H01000000
	Const msiMessageTypeWarning = &H02000000
	Set record = Session.Installer.CreateRecord(0)
  	record.StringData(0) = "checkPHP.vbs -> parseFastCgiIni() -> begin"
	Session.Message msiMessageTypeInfo, record
 
  ' Defaults
  sResult = "none"
  bSection = false
  iLineCount = 0
  sSection = ""
 
  ' Create objects
  Set oFileSystem = CreateObject("Scripting.FileSystemObject")
  Set oFile = oFileSystem.GetFile(sExtension)
    
  If Err.Number = 0 Then 
     ' Set ini file location (expected in the same folder as fcgi dll)
     sPath = Replace(oFile.Path, oFile.Name, "")    
     sIniFile = sPath & "fcgiext.ini"
     
     If oFileSystem.FileExists(sIniFile) Then
        record.StringData(0) = "checkPHP.vbs -> parseFastCgiIni() -> "& sIniFile & " file found"
		Session.Message msiMessageTypeInfo, record
        ' Get ini file contents
        Set oReadFile = oFileSystem.OpenTextFile(sIniFile, 1) 'Reading
        Do Until oReadFile.AtEndOfStream
          ReDim preserve aLines(iLineCount)
          aLines(iLineCount) = oReadFile.Readline
          iLineCount = iLineCount + 1
        Loop
        oReadFile.Close
        
        ' Get interesting section name
        For iCount = LBound(aLines) to UBound(aLines)
          If Left(aLines(iCount), 4) = "php=" Then
            sSection = Replace(aLines(iCount), "php=", "")
            Exit for
          End if
        Next
        
        ' sSection found?
        If Len(sSection) = 0 Then
          parseFastCgiIni = sResult
          Exit function
        End if
        
        ' Get executable
        For iCount = LBound(aLines) to UBound(aLines)
          sLine = Trim(aLines(iCount))
          If Left(sLine, 1) = "[" AND Right(sLine, 1) = "]" Then
            bSection = false
            If LCase(sLine) = "[" & LCase(sSection) & "]" Then
              bSection = true
            End if
          End if
          
          If bSection AND Left(sLine, 8) = "ExePath=" Then
            parseFastCgiIni = Replace(sLine, "ExePath=", "")
            Exit Function
          End if
        Next
	 Else
		record.StringData(0) = "checkPHP.vbs -> parseFastCgiIni() -> "& sIniFile & "file not found! -> error"
		Session.Message msiMessageTypeInfo, record
     End if
	 
     
  End if
  
  parseFastCgiIni = sResult
End Function

Function getExecutable (sExtension)
  Dim oFileSystem, oFile, sPath, sEXE, oFolder
  
  On Error Resume Next
  Err.Clear()
  
  Set oFileSystem = CreateObject("Scripting.FileSystemObject")
  Set oFile = oFileSystem.GetFile(sExtension)
  
  If Err.Number = 0 Then 
     If Right(sEXE, 4) = ".exe" Then
       sEXE = sExtension
     Else
       sPath = Replace(oFile.Path, oFile.Name, "")
       sEXE = sPath & "php.exe"
     End if
     
	   Set oFolder = oFileSystem.getFolder(sPath)
     If oFileSystem.FileExists(sEXE) Then
       getExecutable = oFolder.ShortPath & "\php.exe"
       Exit Function
     End if
  End if

  MsgBox "Unable to locate PHP executable (php.exe)!" & vbCrLf & _ 
         "- Error Details: " & Err.Description & " [Number:" & Hex(Err.Number) & "]", vbCritical, "Error" 
  getExecutable = false 
End Function

Function checkPHPModules(sPHPEXE)
  Dim sModules, oShell, oPHPInfo, sExecString, sLine, aConfiguredModules(), iCount
  Dim aRequiredModules, iRun, sResponse, aTMP, bResult, oFile, sPath
  
  	'for the logging
	Const msiMessageTypeInfo = &H04000000
	Const msiMessageTypeError = &H01000000
	Const msiMessageTypeWarning = &H02000000
	Set record = Session.Installer.CreateRecord(0)
  	record.StringData(0) = "checkPHP.vbs -> checkPHPModules() -> begin"
	Session.Message msiMessageTypeInfo, record
  
  ' Get required modules
  sModules = Session.Property("PHPMODULES")
  aRequiredModules = Split(sModules, ",")
  
  ' Default response and result
  sResponse = "Checking for required PHP modules:" & vbCrLf & vbCrLF
  bResult = True
  
  ' Creating Filesystem object
  Set oFileSystem = CreateObject("Scripting.FileSystemObject")

  ' Get path
  Set oFile = oFileSystem.GetFile(sPHPEXE)
  sPath = Replace(oFile.Path, oFile.Name, "")

  ' Create batch file to process php command (in order to avoid a cmd popup in the installer)
  Set oWriteFile = oFileSystem.OpenTextFile(Session.Property("TempFolder") & "tmpModules.bat", 2, true) 'Writing
     oWriteFile.WriteLine("@Echo off")
     oWriteFile.WriteLine(sPHPEXE & " -m  >%temp%\phpmodules.txt -c " & sPath)
  oWriteFile.Close

  ' Execute batchfile
  Set oShell = CreateObject("WSCript.Shell")
  oShell.Run Session.Property("TempFolder") & "tmpModules.bat" , 0, True
  
  ' Get tmp output file
  Set oReadFile = oFileSystem.OpenTextFile(Session.Property("TempFolder") & "phpmodules.txt", 1) 'Reading

  ' Put all configured php modules into an array
  iCount = 0
  Do Until oReadFile.AtEndOfStream
	  sLine = oReadFile.Readline
	  ReDim preserve aConfiguredModules((iCount + 1))
	  aConfiguredModules(iCount) = Trim(sLine)
	  iCount = iCount + 1
  Loop
  oReadFile.Close()
  
  ' Delete tmp files
  oFileSystem.DeleteFile(Session.Property("TempFolder") & "tmpModules.bat")
  oFileSystem.DeleteFile(Session.Property("TempFolder") & "phpmodules.txt")
  
  
  ' Compare Requirements and 
  For iRun = LBound(aRequiredModules) to UBound(aRequiredModules)
    aTMP = Filter(aConfiguredModules, Trim(aRequiredModules(iRun)))
    If UBound(aTMP) = - 1 Then
      sResponse = sResponse & UCase(Trim(aRequiredModules(iRun))) & VBTab & VBTab & VBTab & "NOT FOUND" & vbCrLf
      bResult = False
    Else
      sResponse = sResponse & UCase(Trim(aRequiredModules(iRun))) & VBTab & VBTab & VBTab & "OK" & vbCrLf    
    End if
  Next
  
  sResponse = sResponse & vbCrLF & "Please add the missing PHP modules by using the PHP MSI Installer or altering the php.ini file." & vbCrLF
  
  If Not bResult Then
     MsgBox sResponse, vbInformation, "Required PHP Modules" 
  End if
  
  checkPHPModules = bResult
End Function


function checkIfIUSRisListedOnPHPUploadDir()
	
	On Error Resume Next
	Err.Clear
	
	'IUSRName = "IIS_IUSRS"
	IUSRName = Session.Property("INTERNETGUESTACCOUNT")
	path = getPHPupload_tmp_dir
	
	Set wmiFileSecSetting = GetObject("winmgmts:Win32_LogicalFileSecuritySetting.path='" & path &"'")

	RetVal = wmiFileSecSetting.GetSecurityDescriptor(wmiSecurityDescriptor)
	
	If Err <> 0 Then 
		writeWindowsInstallerLogEntry "function -> checkIfIUSRisListedOnPHPUploadDir -> GetSecurityDescriptor failed -> Err.Description="&Err.Description,0
	    Exit Function
	End If

	' Retrieve the DACL array of Win32_ACE objects.
	DACL = wmiSecurityDescriptor.DACL

	For each wmiAce in DACL
		' Get Win32_Trustee object from ACE 
		Set Trustee = wmiAce.Trustee
		'check if the AnonymousIISUser is listed for that directory and has an allow ACL with ListFolder / Read Data
		if ((Trustee.Name=IUSRName) and (wmiAce.AceType = 0) and (wmiAce.AccessMask and 2^0)) then
			result = true
			writeWindowsInstallerLogEntry "function -> checkIfIUSRisListedOnPHPUploadDir -> "&IUSRName&" has ListFolder / Read Data permission on " & path,0
			exit for
		else 
			result = false
		end if
	Next

	if (Err.Number <> 0) then
		writeWindowsInstallerLogEntry "function -> checkIfIUSRisListedOnPHPUploadDir -> failed -> Err.Description="&Err.Description,0
	end if
	
	if ((result=false) and (Err.Number=0) ) then
		writeWindowsInstallerLogEntry "function -> checkIfIUSRisListedOnPHPUploadDir -> "& IUSRName & " does not seem to have ListFolder / Read Data permission on " & path,0
		sResponse = "Warning: It seems that the IIS Anonymous User (" & IUSRName & ") does not have the ListFolder / Read Data permission on: " & vbCrLF & path & vbCrLF & "You might need to give ListFolder / Read Data NTFS permission to " & IUSRName & " on this folder."
        MsgBox sResponse, vbInformation, "Required " & IUSRName & " Permissions Warning on PHP upload_tmp_dir"
	end if
			
	checkIfIUSRisListedOnPHPUploadDir = result

end function

function getPHPupload_tmp_dir()
	
	On Error Resume Next
	Err.Clear
	
	tempfolder = Session.Property("TempFolder") 
	sPHPEXE = getExecutable(Session.Property("SCRIPTEXECUTABLE"))
	
	
	Set oFileSystem = CreateObject("Scripting.FileSystemObject")

	  ' Create batch file to process php command (in order to avoid a cmd popup in the installer)
	  Set oWriteFile = oFileSystem.OpenTextFile(tempfolder & "tmpUploadDir.bat", 2, true) 'Writing
	     oWriteFile.WriteLine("@Echo off")
	     oWriteFile.WriteLine(sPHPEXE & " -r phpinfo(INFO_CONFIGURATION); >" & tempfolder & "phpUploadDir.txt")
	  oWriteFile.Close

	  ' Execute batchfile
	  Set oShell = CreateObject("WSCript.Shell")
	  oShell.Run tempfolder & "tmpUploadDir.bat" , 0, True
	  
	  ' Get tmp output file
	  Set oReadFile = oFileSystem.OpenTextFile(tempfolder & "phpUploadDir.txt", 1) 'Reading

	  ' Put all configured php modules into an array
	  iCount = 0
	  Do Until oReadFile.AtEndOfStream
		  sLine = oReadFile.Readline
		  if (InStr(sLine,"upload_tmp_dir"))  then 
	          sLine = Replace(sLine,"upload_tmp_dir","")
			  MyArray = Split(sLine,"=>")
			  if (InStr(MyArray(1),"no value")) then
				'if not defined check the default which is the system temp folder
				'what is the system temp folder
				Set objShell = CreateObject("WScript.Shell")
				Set colSystemEnvVars = objShell.Environment("System")
				Set colProcessEnvVars = objShell.Environment("Process")
				systemTempFolder = colSystemEnvVars("TEMP")
				systemRoot = colProcessEnvVars("SYSTEMROOT")
				upload_tmp_dir = Replace(systemTempFolder,colSystemEnvVars("windir"),systemRoot)
			  else
				upload_tmp_dir = MyArray(1)
			  end if
			  exit do
		  end if
	  Loop
	  oReadFile.Close()
	  
	  ' Delete tmp files
	  oFileSystem.DeleteFile(tempfolder & "tmpUploadDir.bat")
	  oFileSystem.DeleteFile(tempfolder & "phpUploadDir.txt")

	  if (Err.Number = 0) Then 
		writeWindowsInstallerLogEntry "function -> getPHPupload_tmp_dir -> success ->upload_tmp_dir="&upload_tmp_dir,0
	  else
		writeWindowsInstallerLogEntry "function -> getPHPupload_tmp_dir -> failed ->Err.Description="&Err.Description,0
	  end if
	  Err.Clear
	  
	  getPHPupload_tmp_dir = upload_tmp_dir
	  
end function


function writeWindowsInstallerLogEntry(info,infotype)
	
	On Error Resume Next
	Err.Clear
	'infotype can be:
	' 0 for info
	' 1 for warning
	' 2 for error - gives a user prompt - you maybe do not want this.

  	Const msiMessageTypeInfo = &H04000000
	Const msiMessageTypeWarning = &H02000000
	Const msiMessageTypeError = &H01000000

	Set record = Session.Installer.CreateRecord(0)
  	record.StringData(0) = info
	
	select case infotype
		case 0	'information
			Session.Message msiMessageTypeInfo, record
		case 1	'warning
			Session.Message msiMessageTypeWarning, record
		case 2	'error
			Session.Message msiMessageTypeError, record
		case else
			Session.Message msiMessageTypeInfo, record
	end select
	
end function 
